package com.jdd.common.util;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.jdd.common.constant.JddConstant;
import com.jdd.modules.parking.entity.ConfigParkCharge;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;

/**
 * @description: 第三版版计费规则
 * @author: liuyaowen
 * @create: 2021-06-04 17:33
 * @Version 1.0
 **/
@Slf4j
public class ChargeUtil3 {
    private static final Logger logger = LoggerFactory.getLogger(ChargeUtil3.class);

    /**
     * @param dayMoneyLimit 每天最高限额
     * @param days          停车整天数
     * @return int
     * @Description 计算跨天的计费金额
     * @Author zhaishijie
     * @Date 2021-04-01 15:17
     **/
    public static Long crossDayFeeCal(Integer dayMoneyLimit, Long days) {
        logger.info("计算停车时长跨天部分传入参数：每日最高限额：{},停车整天数：{}", dayMoneyLimit, days);
        if (null == days || null == dayMoneyLimit) {
            return 0L;
        }
        return dayMoneyLimit * days;
    }

    /**
     * 计算不足一天的计费金额，分三步计算：1.计算免费时间，2.计算首计时金额，3.计算单位计时金额
     * @param parkCharge 计费规则
     * @param carEnterTime 入场时间
     * @param carOutTime 出场时间
     * @return 不足一天的计费金额
     * @author: liuyaowe
     * @date 2021-06-04
     * */
    public static long unCrossDayFeeCal(ConfigParkCharge parkCharge, Date carEnterTime, Date carOutTime) {
        logger.info("计算停车时长不跨天部分传入参数：车辆入场时间：{},车辆出场时间：{}", DateUtil.format(carEnterTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(carOutTime, "yyyy-MM-dd HH:mm:ss"));
        // 1.计算免费时间
        // 计算停车时长
        long betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);
        // 如果停车时长小于免费时间，且免费时间启用
        if (betweenMinutes < parkCharge.getFreeTime() && JddConstant.ChargeConstant.FREE_TIME_STATUS_OPEN.equals(parkCharge.getFreeTimeStatus())) {
            return 0L;
        }
        // 1、计费规则分时段计费
        if (JddConstant.ChargeConstant.TIME_PERIOD_CAL.equals(parkCharge.getRatesType())) {
            // 2.计算首计时金额
            // 如果停车时间小于首计时单位
            if(betweenMinutes < parkCharge.getFirstUnit())
            {
                return parkCharge.getFirstMoney();
            }
            // 入场时间推进一个首计时单位
            Calendar carEnterCalendar = Calendar.getInstance();
            carEnterCalendar.setTime(carEnterTime);
            carEnterCalendar.add(Calendar.MINUTE, parkCharge.getFirstUnit());
            carEnterTime = carEnterCalendar.getTime();
            // 3.计算单位计时金额
            // 计算除去首计时之后的停车总时间
            betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);
            // 计算停车计时单位数
            long timeUnits = betweenMinutes / parkCharge.getTimeUnit();
            // 计算停车计时余数
            long timeMinutes = Long.valueOf(betweenMinutes % parkCharge.getTimeUnit()).intValue();
            if (timeMinutes != 0) {
                // 如果计时余数大于等于免费时间，或免费时间未启用
                if (timeMinutes >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                    // 停车计时数加1
                    timeUnits++;
                }
            }
            // 停车总金额 = 首计时金额 + 单位计时金额 * 停车计时单位
            long totalMoney = parkCharge.getFirstMoney() + parkCharge.getMoneyUnit() * timeUnits;
            // 如果停车总金额大于每日最高限额
            if (totalMoney > parkCharge.getDayMoneyLimit()) {
                // 返回计算金额：每日最高限额
                return parkCharge.getDayMoneyLimit();
            }
            // 返回计算金额：停车总金额
            return totalMoney;
        }
        // 定义白天计费金额，初始为0
        long dayUnitsMoney = 0;
        // 定义夜晚计费金额，初始为0
        long nightUnitsMoney = 0;
        // 2.计算首计时金额
        // 判断入场时间所在区间类型
        int enterTimeDayOrNight = enterTimeDayOrNight(parkCharge.getDayRegionStartHour(), parkCharge.getDayRegionStartMin(),
                parkCharge.getNightRegionStartHour(), parkCharge.getNightRegionStartMin(), carEnterTime);
        // 如果入场时间是在白天
        if (JddConstant.ChargeConstant.ENTER_DAY == enterTimeDayOrNight) {
            // 如果停车时长小于等于白天首计时单位
            if (betweenMinutes <= parkCharge.getDayRegionFirstUnitMin()) {
                // 返回计算金额：白天首计时金额
                return parkCharge.getDayRegionFirstPrice();
            }
            // 根据入场时间所在区间，推进入场时间
            Calendar carEnterCalendar = Calendar.getInstance();
            carEnterCalendar.setTime(carEnterTime);
            // 将入场时间推进一个白天首计时单位
            carEnterCalendar.add(Calendar.MINUTE, parkCharge.getDayRegionFirstUnitMin());
            carEnterTime = carEnterCalendar.getTime();
            // 白天计费金额 = 白天首计时金额
            dayUnitsMoney = parkCharge.getDayRegionFirstPrice();
        }
        // 如果入场时间是在夜晚
        if (JddConstant.ChargeConstant.ENTER_NIGHT == enterTimeDayOrNight) {
            // 如果停车时长小于等于夜晚首计时单位
            if (betweenMinutes < parkCharge.getNightRegionFirstUnitMin()) {
                // 返回计算金额：夜晚首计时金额
                return parkCharge.getNightRegionFirstPrice();
            }
            // 根据入场时间所在区间，推进入场时间
            Calendar carEnterCalendar = Calendar.getInstance();
            carEnterCalendar.setTime(carEnterTime);
            // 将入场时间推进一个夜晚首计时单位
            carEnterCalendar.add(Calendar.MINUTE, parkCharge.getNightRegionFirstUnitMin());
            carEnterTime = carEnterCalendar.getTime();
            // 夜晚计费金额 = 夜晚首计时金额
            nightUnitsMoney = parkCharge.getNightRegionFirstPrice();
        }
        //入场时间推进后，进场白天还是晚上
        enterTimeDayOrNight = enterTimeDayOrNight(parkCharge.getDayRegionStartHour(), parkCharge.getDayRegionStartMin(),
                parkCharge.getNightRegionStartHour(), parkCharge.getNightRegionStartMin(), carEnterTime);
        //出场白天还是晚上
        int outTimeDayOrNight = outTimeDayOrNight(parkCharge.getDayRegionStartHour(), parkCharge.getDayRegionStartMin(),
                parkCharge.getNightRegionStartHour(), parkCharge.getNightRegionStartMin(), carOutTime);
        //进场白天 出场白天
        if (JddConstant.ChargeConstant.ENTER_DAY == enterTimeDayOrNight && JddConstant.ChargeConstant.OUT_DAY == outTimeDayOrNight) {
            // 如果入场与出场是相同的一天，且不跨时间段
            if (!jdugeNightTime(parkCharge, carEnterTime, carOutTime)) {
                // 计算白天停车总时长
                betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);
                // 计算白天停车计时数
                long dayUnits = betweenMinutes / parkCharge.getDayRegionUnitMin();
                // 计算白天停车计时余数
                long dayMinutes = betweenMinutes % parkCharge.getDayRegionUnitMin();
                // 如果白天计时余数不为0
                if (dayMinutes != 0) {
                    // 如果白天计时余数大于等于免费时间或免费时间未启用
                    if (dayMinutes >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                        // 白天停车计时数加1
                        dayUnits++;
                    }
                }
                // 白天计费金额 = 白天计费金额 + 白天停车计时数 * 白天停车单位计时金额
                dayUnitsMoney = dayUnitsMoney + dayUnits * parkCharge.getDayRegionUnitPrice();
            } else {
                // 如果跨夜晚，得到入场当天的夜晚开始时间
                Calendar nightRegionStartTime = Calendar.getInstance();
                nightRegionStartTime.setTime(carEnterTime);
                nightRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getNightRegionStartHour());
                nightRegionStartTime.set(Calendar.MINUTE, parkCharge.getNightRegionStartMin());
                nightRegionStartTime.set(Calendar.SECOND, 0);
                // 第一段白天计费时长：入场时间到夜晚开始时间
                long dayBetweenMinutes = DateUtil.between(carEnterTime, nightRegionStartTime.getTime(), DateUnit.MINUTE);
                // 得到出场当天的白天开始时间
                Calendar dayRegionStartTime = Calendar.getInstance();
                dayRegionStartTime.setTime(carOutTime);
                dayRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getDayRegionStartHour());
                dayRegionStartTime.set(Calendar.MINUTE, parkCharge.getDayRegionStartMin());
                dayRegionStartTime.set(Calendar.SECOND, 0);
                // 第二段白天计费时长：出场当天的白天开始时间到出场时间
                long secondDayBetweenMinutes = DateUtil.between(dayRegionStartTime.getTime(), carOutTime, DateUnit.MINUTE);
                // 得到白天停车总时长 = 第一段白天停车总时长 + 第二段白天停车总时长
                long dayTotalMinutes = dayBetweenMinutes + secondDayBetweenMinutes;
                // 得到夜晚计费时长
                long nightMinutes = DateUtil.between(dayRegionStartTime.getTime(),nightRegionStartTime.getTime(),DateUnit.MINUTE);
                // 计算白天总计时单位数
                long dayUnits = dayTotalMinutes / parkCharge.getDayRegionUnitMin();
                // 计算白天总计时单位余数
                long dayMinutes = dayTotalMinutes % parkCharge.getDayRegionUnitMin();
                // 计算夜晚总计时单位数
                long nightUnits = nightMinutes/ parkCharge.getNightRegionUnitMin();
                // 如果白天计时余数存在
                if (dayMinutes != 0) {
                    // 如果白天计时余数大于等于免费时间或免费时间未启用
                    if (dayMinutes >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                        // 白天计时数加一
                        dayUnits++;
                    }
                }
                // 白天计费金额 = 白天计费金额 + 白天计时数 * 白天计时单位金额
                dayUnitsMoney = dayUnitsMoney + dayUnits * parkCharge.getDayRegionUnitPrice();
                // 夜晚计费金额 = 夜晚计费金额 + 夜晚计时数 * 夜晚计时单位金额
                nightUnitsMoney = nightUnitsMoney + nightUnits * parkCharge.getNightRegionUnitPrice();
            }
        }
        //进场晚上 出场晚上
        if (JddConstant.ChargeConstant.ENTER_NIGHT == enterTimeDayOrNight && JddConstant.ChargeConstant.OUT_NIGHT == outTimeDayOrNight) {
            // 如果入场与出场是相同的一天，且不跨白天时间段
            if (!jdugeDayTime(parkCharge, carEnterTime, carOutTime)) {
                // 计算夜晚停车总时长
                betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);
                // 计算夜晚停车计时数
                long nightUnits = betweenMinutes / parkCharge.getNightRegionUnitMin();
                // 计算夜晚停车计时余数
                long nightMinutes = betweenMinutes % parkCharge.getNightRegionUnitMin();
                // 如果夜晚计时余数大于免费时间或免费时间未启用
                if (nightMinutes != 0) {
                    if (nightMinutes >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                        // 夜晚计时数加一
                        nightUnits++;
                    }
                }
                // 夜晚计费金额 = 夜晚计费金额 + 夜晚停车计时数 * 夜晚停车每计时单位金额
                nightUnitsMoney = nightUnitsMoney + nightUnits * parkCharge.getNightRegionUnitPrice();
            }
            else {
                // 如果跨白天，得到出场当天的白天开始时间
                Calendar dayRegionStartTime = Calendar.getInstance();
                dayRegionStartTime.setTime(carOutTime);
                dayRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getDayRegionStartHour());
                dayRegionStartTime.set(Calendar.MINUTE, parkCharge.getDayRegionStartMin());
                dayRegionStartTime.set(Calendar.SECOND, 0);
                // 第一段夜晚计费时长：入场时间到出场当天的白天开始时间
                long nightBetweenMinutes = DateUtil.between(carEnterTime, dayRegionStartTime.getTime(), DateUnit.MINUTE);
                // 夜晚开始时间转换成日期
                Calendar nightRegionStartTime = Calendar.getInstance();
                nightRegionStartTime.setTime(carOutTime);
                nightRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getNightRegionStartHour());
                nightRegionStartTime.set(Calendar.MINUTE, parkCharge.getNightRegionStartMin());
                nightRegionStartTime.set(Calendar.SECOND, 0);
                // 第二段夜晚计费时长：出场当天的夜晚开始时间到出场时间
                long secondNightBetweenMinutes = DateUtil.between(nightRegionStartTime.getTime(), carOutTime, DateUnit.MINUTE);
                // 计算夜晚停车总时长
                long nightTotalMinutes = nightBetweenMinutes + secondNightBetweenMinutes;
                // 计算夜晚的计时单位数，和白天的计时单位数
                long nightUnits = nightTotalMinutes / parkCharge.getNightRegionUnitMin();
                long dayUnits = DateUtil.between(nightRegionStartTime.getTime(), dayRegionStartTime.getTime(), DateUnit.MINUTE) / parkCharge.getDayRegionUnitMin();
                // 夜晚计时单位的余数 = 夜晚总计时余数/夜晚停车计时单位
                long nightMinutes = nightTotalMinutes % parkCharge.getNightRegionUnitMin();
                // 夜晚计时单位余数存在
                if (nightMinutes != 0) {
                    // 如果夜晚计时余数大于等于免费时间或免费时间未启用
                    if (nightMinutes >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                        nightUnits++;
                    }
                }
                // 计算夜晚计费金额 = 夜晚计费金额 + 夜晚停车计时数 * 夜晚停车计时单位金额
                nightUnitsMoney =nightUnitsMoney + nightUnits * parkCharge.getNightRegionUnitPrice();
                // 计算白天计费金额 = 白天计费金额 + 白天停车计时数 * 白天停车计时单位金额
                dayUnitsMoney = dayUnitsMoney + dayUnits * parkCharge.getDayRegionUnitPrice() ;
            }
        }
        //进场白天 出场晚上，涉及2段计费
        if (JddConstant.ChargeConstant.ENTER_DAY == enterTimeDayOrNight && JddConstant.ChargeConstant.OUT_NIGHT == outTimeDayOrNight) {
            // 得到出场当天的夜晚开始时间
            Calendar nightRegionStartTime = Calendar.getInstance();
            nightRegionStartTime.setTime(carOutTime);
            nightRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getNightRegionStartHour());
            nightRegionStartTime.set(Calendar.MINUTE, parkCharge.getNightRegionStartMin());
            nightRegionStartTime.set(Calendar.SECOND, 0);
            // 计算第一段白天停车时长：入场时间到出场当天的夜晚开始时间
            long dayBetweenMinutes = DateUtil.between(carEnterTime, nightRegionStartTime.getTime(), DateUnit.MINUTE);
            // 计算白天计时单位
            long dayUnits = dayBetweenMinutes / parkCharge.getDayRegionUnitMin();
            // 计算白天计时单位余数
            long dayMinutes = dayBetweenMinutes % parkCharge.getDayRegionUnitMin();
            // 计算第二段晚上
            long nightBetweenMinutes = DateUtil.between(nightRegionStartTime.getTime(), carOutTime, DateUnit.MINUTE);
            // 计算夜晚计时单位
            long nightUnits = nightBetweenMinutes / parkCharge.getNightRegionUnitMin();
            // 计算夜晚计时单位余数
            long nightMinutes = nightBetweenMinutes % parkCharge.getNightRegionUnitMin();
            // 计算总计时余数
            long totalMinutes = dayMinutes + nightMinutes;
            // 白天计时余数是否大于夜晚计时余数
            if (dayMinutes > nightMinutes) {
                // 大于，则白天计时数 = 白天计时数 + 总计时余数/白天计时单位
                dayUnits = dayUnits + (totalMinutes / parkCharge.getDayRegionUnitMin());
                // 总计时余数除以白天计时单位的余数是否大于免费时间或免费时间未启用
                if (totalMinutes % parkCharge.getDayRegionUnitMin() >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                    // 白天计时数+1
                    dayUnits = dayUnits + 1;
                }
            } else {
                // 小于或等于，则夜晚计时数 = 夜晚计时数 + 总计时余数/夜晚计时单位
                nightUnits = nightUnits + (totalMinutes / parkCharge.getNightRegionUnitMin());
                // 总计时余数除以夜晚计时单位的余数是否大于免费时间或免费时间未启用
                if (totalMinutes % parkCharge.getNightRegionUnitMin() >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                    // 夜晚计时数+1
                    nightUnits = nightUnits + 1;
                }
            }
            dayUnitsMoney = dayUnitsMoney + dayUnits * parkCharge.getDayRegionUnitPrice() ;
            nightUnitsMoney = nightUnitsMoney + nightUnits * parkCharge.getNightRegionUnitPrice();
        }
        //进场晚上 出场白天，涉及2段计费
        if (JddConstant.ChargeConstant.ENTER_NIGHT == enterTimeDayOrNight && JddConstant.ChargeConstant.OUT_DAY == outTimeDayOrNight) {

            // 计算白天开始时间
            Calendar dayRegionStartTime = Calendar.getInstance();
            dayRegionStartTime.setTime(carOutTime);
            dayRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getDayRegionStartHour());
            dayRegionStartTime.set(Calendar.MINUTE, parkCharge.getDayRegionStartMin());
            dayRegionStartTime.set(Calendar.SECOND, 0);
            // 根据入场时间和夜晚开始时间，计算第一段晚上停车时长
            long nightBetweenMinutes = DateUtil.between(carEnterTime, dayRegionStartTime.getTime(), DateUnit.MINUTE);
            // 计算夜晚计时单位
            long nightUnits = nightBetweenMinutes / parkCharge.getNightRegionUnitMin();
            // 计算夜晚计时单位余数
            long nightMinutes = nightBetweenMinutes % parkCharge.getNightRegionUnitMin();
            // 根据夜晚开始时间和出场时间，计算第二段白天停车时长
            long dayBetweenMinutes = DateUtil.between(dayRegionStartTime.getTime(), carOutTime, DateUnit.MINUTE);
            // 计算白天计时单位
            long dayUnits = dayBetweenMinutes / parkCharge.getDayRegionUnitMin();
            // 计算白天计时单位余数
            long dayMinutes = dayBetweenMinutes % parkCharge.getDayRegionUnitMin();
            // 计算总计时单位余数
            long totalMinutes = dayMinutes + nightMinutes;
            // 夜晚计时余数是否大于白天计时余数
            if (nightMinutes > dayMinutes) {
                // 大于，夜晚计时数 = 夜晚计时数 + 总计时单位余数/夜晚计时单位
                nightUnits = nightUnits + (totalMinutes / parkCharge.getNightRegionUnitMin());
                // 总计时单位余数除以夜晚计时单位的余数 大于免费时间或免费时间未启用
                if (totalMinutes % parkCharge.getNightRegionUnitMin() >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                    // 夜晚计时数+1
                    nightUnits = nightUnits + 1;
                }
            } else {
                // 小于，等于， 白天计时数 = 白天计时数 + 总计时单位余数/白天计时单位
                dayUnits = dayUnits + (totalMinutes / parkCharge.getDayRegionUnitMin());
                // 总计时单位余数除以白天计时单位的余数 大于免费时间或免费时间未启用
                if (totalMinutes % parkCharge.getDayRegionUnitMin() >= parkCharge.getFreeTime() || JddConstant.ChargeConstant.FREE_TIME_STATUS_CLOSE.equals(parkCharge.getFreeTimeStatus())) {
                    // 白天计时数+1
                    dayUnits = dayUnits + 1;
                }
            }
            dayUnitsMoney = dayUnitsMoney + dayUnits * parkCharge.getDayRegionUnitPrice() ;
            nightUnitsMoney = nightUnitsMoney + nightUnits * parkCharge.getNightRegionUnitPrice();
        }
        if(nightUnitsMoney > parkCharge.getNightRegionMaxPrice()){
            nightUnitsMoney = parkCharge.getNightRegionMaxPrice();
        }
        if(dayUnitsMoney > parkCharge.getDayRegionMaxPrice())
        {
            dayUnitsMoney = parkCharge.getDayRegionMaxPrice();
        }
        long dayTotalMoney = dayUnitsMoney + nightUnitsMoney ;
        if (dayTotalMoney > parkCharge.getDayMoneyLimit()) {
            return parkCharge.getDayMoneyLimit();
        }
        return dayTotalMoney;
    }


    /**
     * @param parkCharge   计费规则
     * @param carEnterTime 车辆进场时间
     * @param carOutTime   车辆出场时间
     * @return boolean
     * @Description 判断停车时长是否跨白天
     * @Author zhaishijie
     * @Date 2021-04-01 15:23
     **/
    public static boolean jdugeDayTime(ConfigParkCharge parkCharge, Date carEnterTime, Date carOutTime) {
        //停车时长
        long betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);

        //获取晚上区间的分钟数
        //晚上开始时间
        Calendar nightRegionStartTime = Calendar.getInstance();
        nightRegionStartTime.setTime(carEnterTime);
        nightRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getNightRegionStartHour());
        nightRegionStartTime.set(Calendar.MINUTE, parkCharge.getNightRegionStartMin());
        nightRegionStartTime.set(Calendar.SECOND, 0);

        //晚上结束时间
        Calendar nightRegionEndTime = Calendar.getInstance();
        nightRegionEndTime.setTime(carEnterTime);
        nightRegionEndTime.add(Calendar.DATE, 1);
        nightRegionEndTime.set(Calendar.HOUR_OF_DAY, parkCharge.getDayRegionStartHour());
        nightRegionEndTime.set(Calendar.MINUTE, parkCharge.getDayRegionStartMin());
        nightRegionEndTime.set(Calendar.SECOND, 0);


        long nightBetweenMinutes = DateUtil.between(nightRegionStartTime.getTime(), nightRegionEndTime.getTime(), DateUnit.MINUTE);
        if (betweenMinutes <= nightBetweenMinutes) {
            return false;
        }
        return true;
    }

    /**
     * @param parkCharge   计费规则
     * @param carEnterTime 车辆进场时间
     * @param carOutTime   车辆出场时间
     * @return boolean
     * @Description 判断停车时长是否跨晚上
     * @Author zhaishijie
     * @Date 2021-04-01 15:23
     **/
    public static boolean jdugeNightTime(ConfigParkCharge parkCharge, Date carEnterTime, Date carOutTime) {
        //停车时长
        long betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);

        //获取白天区间的分钟数
        //白天开始时间
        Calendar dayRegionStartTime = Calendar.getInstance();
        dayRegionStartTime.setTime(carEnterTime);
        dayRegionStartTime.set(Calendar.HOUR_OF_DAY, parkCharge.getDayRegionStartHour());
        dayRegionStartTime.set(Calendar.MINUTE, parkCharge.getDayRegionStartMin());
        dayRegionStartTime.set(Calendar.SECOND, 0);

        //白天结束时间
        Calendar dayRegionEndTime = Calendar.getInstance();
        dayRegionEndTime.setTime(carEnterTime);
        dayRegionEndTime.set(Calendar.HOUR_OF_DAY, parkCharge.getNightRegionStartHour());
        dayRegionEndTime.set(Calendar.MINUTE, parkCharge.getNightRegionStartMin());
        dayRegionEndTime.set(Calendar.SECOND, 0);

        long nightBetweenMinutes = DateUtil.between(dayRegionStartTime.getTime(), dayRegionEndTime.getTime(), DateUnit.MINUTE);
        if (betweenMinutes <= nightBetweenMinutes) {
            return false;
        }
        return true;
    }

    /**
     * @param parkCharge   计费规则
     * @param carEnterTime 车辆进场时间
     * @param carOutTime   车辆出场时间
     * @return int
     * @Description 停车总金额计算
     * @Author zhaishijie
     * @Date 2021-04-01 15:23
     **/
    public static long totalFeeCal(ConfigParkCharge parkCharge, Date carEnterTime, Date carOutTime) {
        logger.info("计算停车总金额传入参数：车辆入场时间：{},车辆出场时间：{}", DateUtil.format(carEnterTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(carOutTime, "yyyy-MM-dd HH:mm:ss"));
        //1.计算停车整天数的费用
        //计算停车时长分钟数
        long betweenMinutes = DateUtil.between(carEnterTime, carOutTime, DateUnit.MINUTE);
        long days = betweenMinutes / JddConstant.ChargeConstant.DAY_NIGHT_MINUTES;
        long daysRemainder = betweenMinutes % JddConstant.ChargeConstant.DAY_NIGHT_MINUTES;
        // 计费时长不满一天
        if (days == 0 && daysRemainder > 0) {
            long unCrossDayFee = unCrossDayFeeCal(parkCharge, carEnterTime, carOutTime);
            logger.info("停车时长不满一天计算结果：{}", unCrossDayFee);
            return unCrossDayFee;
        }
        // 计算整天的停车费用
        long crossDayFee = crossDayFeeCal(parkCharge.getDayMoneyLimit(), days);
        //判断是否存在不满整天的余数 停车整数天并且没有余数
        if (daysRemainder == 0) {
            return crossDayFee;
        }
        logger.info("停车时长整天数计算结果：{}", crossDayFee);
        //2.计算停车不满一天数的费用
        // 计算平移时间
        Calendar carEnterCal = Calendar.getInstance();
        carEnterCal.setTime(carEnterTime);
        carEnterCal.add(Calendar.DAY_OF_MONTH, (int) days);
        long unCrossDayFee = unCrossDayFeeCal(parkCharge, carEnterCal.getTime(), carOutTime);
        logger.info("停车时长不满一天计算结果：{}", unCrossDayFee);
        return unCrossDayFee + crossDayFee;
    }

    /**
     * @param dayRegionStartHour   区间白天开始小时
     * @param dayRegionStartMin    区间白天开始分钟
     * @param nightRegionStartHour 区间夜晚开始小时
     * @param nightRegionStartMin  区间夜晚开始分钟
     * @param enterTime            车辆入场时间
     * @return int
     * @Description 计算进场时间是白天还是夜晚, 临界值均为晚上时段
     * @Author zhaishijie
     * @Date 2021-04-01 15:56
     **/
    public static int enterTimeDayOrNight(Integer dayRegionStartHour, Integer dayRegionStartMin, Integer nightRegionStartHour, Integer nightRegionStartMin, Date enterTime) {
        //因Date类的很多方法已废弃,故将入场时间转换为Calendar类
        Calendar enterTimeTmp = Calendar.getInstance();
        enterTimeTmp.setTime(enterTime);
        // 白天时段换算成时间
        Calendar dayRegionStartTime = Calendar.getInstance();
        dayRegionStartTime.set(Calendar.YEAR, enterTimeTmp.get(Calendar.YEAR));
        dayRegionStartTime.set(Calendar.MONTH, enterTimeTmp.get(Calendar.MONTH));
        dayRegionStartTime.set(Calendar.DAY_OF_MONTH, enterTimeTmp.get(Calendar.DAY_OF_MONTH));
        dayRegionStartTime.set(Calendar.HOUR_OF_DAY, dayRegionStartHour);
        dayRegionStartTime.set(Calendar.MINUTE, dayRegionStartMin);
        dayRegionStartTime.set(Calendar.SECOND, 0);
        dayRegionStartTime.set(Calendar.MILLISECOND, 0);

        // 晚上时段换算成时间
        Calendar nightRegionStartTime = Calendar.getInstance();
        nightRegionStartTime.set(Calendar.YEAR, enterTimeTmp.get(Calendar.YEAR));
        nightRegionStartTime.set(Calendar.MONTH, enterTimeTmp.get(Calendar.MONTH));
        nightRegionStartTime.set(Calendar.DAY_OF_MONTH, enterTimeTmp.get(Calendar.DAY_OF_MONTH));
        nightRegionStartTime.set(Calendar.HOUR_OF_DAY, nightRegionStartHour);
        nightRegionStartTime.set(Calendar.MINUTE, nightRegionStartMin);
        nightRegionStartTime.set(Calendar.SECOND, 0);
        nightRegionStartTime.set(Calendar.MILLISECOND, 0);

        if (enterTime.getTime() == dayRegionStartTime.getTime().getTime() || (enterTime.after(dayRegionStartTime.getTime()) && enterTime.before(nightRegionStartTime.getTime()) && enterTime.getTime() != nightRegionStartTime.getTime().getTime())) {
            return JddConstant.ChargeConstant.ENTER_DAY;
        } else {
            return JddConstant.ChargeConstant.ENTER_NIGHT;
        }
    }

    /**
     * @param dayRegionStartHour   区间白天开始小时
     * @param dayRegionStartMin    区间白天开始分钟
     * @param nightRegionStartHour 区间夜晚开始小时
     * @param nightRegionStartMin  区间夜晚开始分钟
     * @param outTime              车辆出场时间
     * @return int
     * @Description 计算出场时间是白天还是夜晚, 临界值均为晚上时段
     * @Author zhaishijie
     * @Date 2021-04-01 15:56
     **/
    public static int outTimeDayOrNight(Integer dayRegionStartHour, Integer dayRegionStartMin, Integer nightRegionStartHour, Integer nightRegionStartMin, Date outTime) {
        //因Date类的很多方法已废弃,故将出场时间转换为Calendar类
        Calendar outTimeTmp = Calendar.getInstance();
        outTimeTmp.setTime(outTime);
        // 白天时段换算成时间
        Calendar dayRegionStartTime = Calendar.getInstance();
        dayRegionStartTime.set(Calendar.YEAR, outTimeTmp.get(Calendar.YEAR));
        dayRegionStartTime.set(Calendar.MONTH, outTimeTmp.get(Calendar.MONTH));
        dayRegionStartTime.set(Calendar.DAY_OF_MONTH, outTimeTmp.get(Calendar.DAY_OF_MONTH));
        dayRegionStartTime.set(Calendar.HOUR_OF_DAY, dayRegionStartHour);
        dayRegionStartTime.set(Calendar.MINUTE, dayRegionStartMin);
        dayRegionStartTime.set(Calendar.SECOND, 0);
        dayRegionStartTime.set(Calendar.MILLISECOND, 0);
        // 晚上时段换算成时间
        Calendar nightRegionStartTime = Calendar.getInstance();
        nightRegionStartTime.set(Calendar.YEAR, outTimeTmp.get(Calendar.YEAR));
        nightRegionStartTime.set(Calendar.MONTH, outTimeTmp.get(Calendar.MONTH));
        nightRegionStartTime.set(Calendar.DAY_OF_MONTH, outTimeTmp.get(Calendar.DAY_OF_MONTH));
        nightRegionStartTime.set(Calendar.HOUR_OF_DAY, nightRegionStartHour);
        nightRegionStartTime.set(Calendar.MINUTE, nightRegionStartMin);
        nightRegionStartTime.set(Calendar.SECOND, 0);
        nightRegionStartTime.set(Calendar.MILLISECOND, 0);

        if (outTime.getTime() == dayRegionStartTime.getTime().getTime() || (outTime.after(dayRegionStartTime.getTime()) && outTime.before(nightRegionStartTime.getTime()) && outTime.getTime() != nightRegionStartTime.getTime().getTime())) {
            return JddConstant.ChargeConstant.OUT_DAY;
        } else {
            return JddConstant.ChargeConstant.OUT_NIGHT;
        }
    }

    /**
     * @param dayMinutes   白天计时余数
     * @param nightMinutes 夜晚计时余数
     * @param parkCharge   计费规则
     * @return
     * @Description: 判断白天计时余数与夜晚计时余数在各自停车计时单位中占比的大小
     * @date 2021-06-04
     */
    public static int judgeFeeRulesByTimeMinutesRatio(long dayMinutes, long nightMinutes, ConfigParkCharge parkCharge) {

        BigDecimal dayMinutesProportion = new BigDecimal(dayMinutes).divide(new BigDecimal(parkCharge.getDayRegionUnitMin()), 2, BigDecimal.ROUND_HALF_DOWN);
        BigDecimal nightMinutesProportion = new BigDecimal(nightMinutes).divide(new BigDecimal(parkCharge.getNightRegionUnitMin()), 2, BigDecimal.ROUND_HALF_DOWN);
        if (dayMinutesProportion.compareTo(nightMinutesProportion) > 0) {
            return JddConstant.ChargeConstant.FEE_MINUTES_COMPARE_GREATER;
        }
        if (dayMinutesProportion.compareTo(nightMinutesProportion) < 0) {
            return JddConstant.ChargeConstant.FEE_MINUTES_COMPARE_LESS;
        }
        return JddConstant.ChargeConstant.FEE_MINUTES_COMPARE_EQUAL;
    }
}
